package com.cppsu.cgx.libraryseatselection.services.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.cppsu.cgx.libraryseatselection.common.api.ResultCode;
import com.cppsu.cgx.libraryseatselection.common.utils.JwtTokenUtil;
import com.cppsu.cgx.libraryseatselection.dto.UserDto;
import com.cppsu.cgx.libraryseatselection.dto.UserLoginParam;
import com.cppsu.cgx.libraryseatselection.dto.UserParam;
import com.cppsu.cgx.libraryseatselection.entity.Admin;
import com.cppsu.cgx.libraryseatselection.entity.User;
import com.cppsu.cgx.libraryseatselection.exception.ApiException;
import com.cppsu.cgx.libraryseatselection.mapper.AdminDynamicSqlSupport;
import com.cppsu.cgx.libraryseatselection.mapper.AdminMapper;
import com.cppsu.cgx.libraryseatselection.mapper.UserDynamicSqlSupport;
import com.cppsu.cgx.libraryseatselection.mapper.UserMapper;
import com.cppsu.cgx.libraryseatselection.services.AdminService;
import com.cppsu.cgx.libraryseatselection.services.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

import static org.mybatis.dynamic.sql.SqlBuilder.*;

/**
 * @Author: guibo
 * @Description:
 * @Date: Created in 10:59 2021/3/10
 * @Modified By:
 */
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    UserMapper userMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    UserDetailsService userDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private AdminMapper adminMapper;


    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Override
    public List<UserDto> list(UserParam userParam) {
        List<UserDto> userDtoList = new ArrayList<>();
        List<User> users =  userMapper.select(c->c
                .where(UserDynamicSqlSupport.id,isEqualToWhenPresent(userParam.getId()))
                .and(UserDynamicSqlSupport.type,isEqualToWhenPresent(userParam.getType()))
                .and(UserDynamicSqlSupport.sex,isEqualToWhenPresent(userParam.getSex()))
                .and(UserDynamicSqlSupport.phone,isLikeWhenPresent(userParam.getPhone()).then(s->"%"+s+"%"))
                .and(UserDynamicSqlSupport.name,isLikeWhenPresent(userParam.getName()).then(s->"%"+s+"%"))
                .and(UserDynamicSqlSupport.number,isLikeWhenPresent(userParam.getNumber()).then(s->"%"+s+"%"))
        );
        for(User user:users){
            UserDto userDto = new UserDto();
            BeanUtils.copyProperties(user,userDto);
            userDtoList.add(userDto);
        }
        return userDtoList;
    }

    @Override
    public int add(UserParam userParam) {
        userParam.setId(null);
        if(!userMapper.select(c->c.where(UserDynamicSqlSupport.number,isEqualTo(userParam.getNumber()))).isEmpty())
            throw new ApiException("用户名已存在");
        User record = new User();
        BeanUtils.copyProperties(userParam,record);
        String encodePassword = passwordEncoder.encode(record.getPassword());
        record.setPassword(encodePassword);
        return userMapper.insertSelective(record);
    }

    @Override
    public int update(UserParam userParam) {
        User record = new User();
        BeanUtils.copyProperties(userParam,record);
        return userMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public int delete(List<Long> ids) {
        return userMapper.delete(c->c.where(UserDynamicSqlSupport.id,isIn(ids)));
    }

    @Override
    public String login(UserLoginParam userLoginParam) {
        String token = null;
        try {
            UserDetails userDetails = userDetailsService.loadUserByUsername(userLoginParam.getUsername());
            if (!passwordEncoder.matches(userLoginParam.getPassword(), userDetails.getPassword())|| !userLoginParam.getPassword().equals(userDetails.getPassword())) {
                throw new BadCredentialsException("密码不正确");
            }
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.generateToken(userDetails);
        } catch (AuthenticationException ignored) {

        }
        return token;
    }

    @Override
    public User getCurrentUser() {
        String userStr = request.getHeader("Authorization");
        if(StrUtil.isEmpty(userStr)){
            throw  new ApiException(ResultCode.UNAUTHORIZED);
        }
        String token = userStr.replace("Bearer ","");
        String username = jwtTokenUtil.getUserNameFromToken(token);
        List<User> users =  userMapper.select(c->c.where(UserDynamicSqlSupport.number,isEqualTo(username)));
        if(users!=null&&!users.isEmpty()){
            return users.get(0);
        }
        throw  new ApiException(ResultCode.FORBIDDEN);
    }

    @Override
    public int updatePassword(String oldPassword,String newPassword) {
        User user = getCurrentUser();
        if(!passwordEncoder.matches(oldPassword,user.getPassword())||!oldPassword.equals(user.getPassword())){
            throw new ApiException("密码错误");
        }
        user.setPassword(passwordEncoder.encode(newPassword));
        return userMapper.updateByPrimaryKeySelective(user);
    }
}
